﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using OpenComposite.Base.Collections;
using OpenComposite.HumanActivity.Contracts.Participants;
using OpenComposite.Repository.Properties;
using OpenComposite.EII.RepositoryUIs;
using System.Diagnostics;

namespace OpenComposite.EII.Repository
{
	[RepositoryItem(ItemType.User, "users", "user_id")]
	public class User : RepositoryItemBaseEx, IParticipant
	{
		#region Initialization
		public User()
			: base("user_id", "person_nm", "person_desc", "person_ntext", Resources.sNewPerson)
		{
		}
		public User(bool bCreateNew)
			: this()
		{
			if ( bCreateNew )
				this.CreateNew();
		}
		public User(int id)
			: this()
		{
			this.Load(id);
		}
		#endregion

		#region Public Properties

		#region Override
		/// <summary>
		/// Gets the image key.
		/// </summary>
		/// <value>The image key.</value>
		public override string ImageKey
		{
			get { return "png_user"; }
		}

		/// <summary>
		/// Gets the selected image key.
		/// </summary>
		/// <value>The selected image key.</value>
		public override string SelectedImageKey
		{
			get { return "png_user"; }
		}

		/// <summary>
		/// Gets the image.
		/// </summary>
		/// <value>The image.</value>
		public override System.Drawing.Image Image
		{
			get { return Resources.png_user; }
		}

		/// <summary>
		/// Gets the selected image.
		/// </summary>
		/// <value>The selected image.</value>
		public override System.Drawing.Image SelectedImage
		{
			get { return Resources.png_user; }
		}

		/// <summary>
		/// Gets the type of the repository item.
		/// </summary>
		/// <value>The type of the repository item.</value>
		public override ItemType RepositoryItemType
		{
			get { return ItemType.User; }
		}

		/// <summary>
		/// Gets the name of the repository item type.
		/// </summary>
		/// <value>The name of the repository item type.</value>
		public override string RepositoryItemTypeName
		{
			get { return "User"; }
		}

		/// <summary>
		/// Gets the repository item type description.
		/// </summary>
		/// <value>The repository item type description.</value>
		public override string RepositoryItemTypeDescription
		{
			get { return ""; }
		}

		/// <summary>
		/// Gets the name of the table.
		/// </summary>
		/// <value>The name of the table.</value>
		public override string TableName
		{
			get { return "t_person"; }
		}

		/// <summary>
		/// Gets the allowed child types.
		/// </summary>
		/// <value>The allowed child types.</value>
		public override List<ItemType> AllowedChildTypes
		{
			get
			{
				List<ItemType> list = new List<ItemType>();
				list.Add(ItemType.OrgUnit);
				return list;
			}
		}

		/// <summary>
		/// Gets or sets the name.
		/// </summary>
		/// <value>The name.</value>
		public override string Name
		{
			get { return FormattedName; }
			set
			{
				if ( value == Resources.sNewPerson ) {
					return;
				}
				string[] parts = value.Split(',');
				if ( parts.Length == 2 ) {
					this.LastName = parts[0];
					string[] firstNameParts = parts[1].Split(' ');
					if ( parts.Length == 2 ) {
						this.FirstName = firstNameParts[0];
						this.MiddleInitials = firstNameParts[1];
					} else {
						this.FirstName = firstNameParts[0];
					}
				} else {
					this.LastName = value;
				}
			}
		}
		#endregion

		#region Person Data

		/// <summary>
		/// Gets or sets the organisation unit ID.
		/// </summary>
		/// <value>The organisation unit ID.</value>
		public int OrganizationUnitId
		{
			get { return getInt("person_orgunit", -1); }
			set { setValue("OrganizationUnitId", "person_orgunit", value); }
		}
		/// <summary>
		/// Gets or sets the organizational unit.
		/// </summary>
		/// <value>The organizational unit.</value>
		public OrganizationalUnit OrganizationalUnit
		{
			get { return RepositoryService.GetItem<OrganizationalUnit>(OrganizationUnitId); }
			set { OrganizationUnitId = ( value == null ? -1 : value.ID ); }
		}

		/// <summary>
		/// Gets or sets the organisation.
		/// </summary>
		/// <value>The organisation.</value>
		public Organization Organization
		{
			get { return RepositoryService.GetItem<Organization>(OrganizationId); }
			set
			{
				if ( value == null ) throw new NullReferenceException("The user must be assigned to an organization.");
				this.OrganizationId = value.ID;
			}
		}

		/// <summary>
		/// Gets or sets the employee ID.
		/// </summary>
		/// <value>The employee ID.</value>
		public string EmployeeId
		{
			get { return getString(_names.sColEmployeeID, ID.ToString()); }
			set { setValue("EmployeeId", _names.sColEmployeeID, value); }
		}

		/// <summary>
		/// Gets or sets the first name.
		/// </summary>
		/// <value>The first name.</value>
		public string FirstName
		{
			get { return getString(_names.sColFirstName, "").TrimEnd(); }
			set { setValue("FirstName", _names.sColFirstName, value); }
		}

		/// <summary>
		/// Gets or sets the last name.
		/// </summary>
		/// <value>The last name.</value>
		public string LastName
		{
			get { return getString(_names.sColLastName, "").TrimEnd(); }
			set { setValue("LastName", _names.sColLastName, value); }
		}

		/// <summary>
		/// Gets or sets the middle initials.
		/// </summary>
		/// <value>The middle initials.</value>
		public string MiddleInitials
		{
			get { return getString(_names.sColMiddleName, ""); }
			set { setValue("MiddleInitials", _names.sColMiddleName, value); }
		}

		/// <summary>
		/// Gets or sets the name of the user.
		/// </summary>
		/// <value>The name of the user.</value>
		public string UserName
		{
			get { return getString(_names.sColUserName, ""); }
			set { setValue("UserName", _names.sColUserName, value); }
		}

		/// <summary>
		/// Gets or sets the password.
		/// </summary>
		/// <value>The password.</value>
		public string Password
		{
			get { return getString(_names.sColPassword, ""); }
			set
			{
				if ( value.Length == 88 && value.EndsWith("==") ) return;
				setValue("Password", _names.sColPassword, OpenComposite.Base.Helper.GetHashedString(value));
			}
		}

		/// <summary>
		/// Gets the name of the formatted.
		/// </summary>
		/// <value>The name of the formatted.</value>
		public string FormattedName
		{
			get
			{
				if ( ID <= 0 ) return "None";
				return string.Format("{0}, {1} {2}", LastName, FirstName, MiddleInitials).Trim();
			}
		}

		/// <summary>
		/// Gets or sets the roles.
		/// </summary>
		/// <value>The roles.</value>
		public Role[] Roles
		{
			get
			{
				return Global.Data.GetOrgRolesByOrgUser(this.ID).ToArray();
			}
			set
			{
				Global.Data.UpdateOrgUserRoles(this.ID, value);
			}
		}

		/// <summary>
		/// Adds the role.
		/// </summary>
		/// <param name="role">The role.</param>
		public void AddRole(Role role)
		{
			List<Role> newRoles = new List<Role>(Roles);
			if ( newRoles.Contains(role) ) return;
			newRoles.Add(role);
			Roles = newRoles.ToArray();
		}

		/// <summary>
		/// Removes the role.
		/// </summary>
		/// <param name="role">The role.</param>
		public void RemoveRole(Role role)
		{
			List<Role> newRoles = new List<Role>(Roles);
			newRoles.Remove(role);
			Roles = newRoles.ToArray();
		}

		/// <summary>
		/// Gets or sets the title.
		/// </summary>
		/// <value>The title.</value>
		public string Title
		{
			get { return base.getString(_names.sColTitle, ""); }
			set { base.setValue("Title", _names.sColTitle, value); }
		}

		/// <summary>
		/// Gets or sets the phone private1.
		/// </summary>
		/// <value>The phone private1.</value>
		public string PhonePrivate1
		{
			get { return base.getString("home_phone", ""); }
			set { base.setValue("PhonePrivate1", "home_phone", value); }
		}

		/// <summary>
		/// Gets or sets the phone private2.
		/// </summary>
		/// <value>The phone private2.</value>
		public string PhonePrivate2
		{
			get { return base.getString("home_phone_2", ""); }
			set { base.setValue("PhonePrivate2", "home_phone_2", value); }
		}

		/// <summary>
		/// Gets or sets the phone mobile.
		/// </summary>
		/// <value>The phone mobile.</value>
		public string PhoneMobile
		{
			get { return base.getString("mobile_phone", ""); }
			set { base.setValue("PhoneMobile", "mobile_phone", value); }
		}

		/// <summary>
		/// Gets or sets the address.
		/// </summary>
		/// <value>The address.</value>
		public string Address
		{
			get { return base.getString("addr", ""); }
			set { base.setValue("Address", "addr", value); }
		}

		/// <summary>
		/// Gets or sets the city.
		/// </summary>
		/// <value>The city.</value>
		public string City
		{
			get { return base.getString("city", ""); }
			set { base.setValue("Address", "city", value); }
		}

		/// <summary>
		/// Gets or sets the state.
		/// </summary>
		/// <value>The state.</value>
		public string State
		{
			get { return base.getString("state", ""); }
			set { base.setValue("State", "state", value); }
		}

		/// <summary>
		/// Gets or sets the zip code.
		/// </summary>
		/// <value>The zip code.</value>
		public string ZipCode
		{
			get { return base.getString("zip", ""); }
			set { base.setValue("ZipCode", "zip", value); }
		}

		/// <summary>
		/// Gets or sets the country.
		/// </summary>
		/// <value>The country.</value>
		public string Country
		{
			get { return base.getString("country", ""); }
			set { base.setValue("Country", "country", value); }
		}

		/// <summary>
		/// Gets or sets the language code.
		/// </summary>
		/// <value>The language code.</value>
		public int LanguageCode
		{
			get { return base.getInt("lcid", -1); }
			set { base.setValue("LanguageCode", "lcid", value); }
		}

		/// <summary>
		/// Gets or sets the language ID.
		/// </summary>
		/// <value>The language ID.</value>
		public int LanguageId
		{
			get { return base.getInt("lang_id", -1); }
			set { base.setValue("LanguageId", "lang_id", value); }
		}

		/// <summary>
		/// Gets or sets the pager.
		/// </summary>
		/// <value>The pager.</value>
		public string Pager
		{
			get { return base.getString("pager", ""); }
			set { base.setValue("Pager", "pager", value); }
		}

		/// <summary>
		/// Gets or sets the office.
		/// </summary>
		/// <value>The office.</value>
		public string Office
		{
			get { return base.getString("office", ""); }
			set { base.setValue("Pager", "office", value); }
		}

		/// <summary>
		/// Gets or sets the phone business1.
		/// </summary>
		/// <value>The phone business1.</value>
		public string PhoneBusiness1
		{
			get { return base.getString("work_phone", ""); }
			set { base.setValue("Pager", "work_phone", value); }
		}

		/// <summary>
		/// Gets or sets the phone business2.
		/// </summary>
		/// <value>The phone business2.</value>
		public string PhoneBusiness2
		{
			get { return base.getString("business_phone_2", ""); }
			set { base.setValue("Pager", "business_phone_2", value); }
		}

		/// <summary>
		/// Gets or sets the fax.
		/// </summary>
		/// <value>The fax.</value>
		public string Fax
		{
			get { return base.getString("fax_no", ""); }
			set { base.setValue("Pager", "fax_no", value); }
		}

		/// <summary>
		/// Gets or sets the email.
		/// </summary>
		/// <value>The email.</value>
		public string Email
		{
			get { return base.getString("email_addr", ""); }
			set { base.setValue("Email", "email_addr", value); }
		}

		/// <summary>
		/// Gets or sets the phone assistant ID.
		/// </summary>
		/// <value>The phone assistant ID.</value>
		public string PhoneAssistantID
		{
			get { return base.getString("assistant_phone", ""); }
			set { base.setValue("PhoneAssistantID", "assistant_phone", value); }
		}

		/// <summary>
		/// Gets or sets the first assistant ID.
		/// </summary>
		/// <value>The first assistant ID.</value>
		public int FirstAssistantID
		{
			get { return base.getInt("mgr1_assist_user_id", -1); }
			set { base.setValue("FirstAssistantID", "mgr1_assist_user_id", value); }
		}

		/// <summary>
		/// Gets or sets the first assistant.
		/// </summary>
		/// <value>The first assistant.</value>
		public User FirstAssistant
		{
			get { return RepositoryService.GetItem<User>(FirstAssistantID); }
			set
			{
				if ( value == null ) {
					FirstAssistantID = -1;
				} else {
					FirstAssistantID = value.ID;
				}
			}
		}

		/// <summary>
		/// Gets or sets the second assistant ID.
		/// </summary>
		/// <value>The second assistant ID.</value>
		public int SecondAssistantID
		{
			get { return base.getInt("mgr2_assist_user_id", -1); }
			set { base.setValue("SecondAssistantID", "mgr2_assist_user_id", value); }
		}

		/// <summary>
		/// Gets or sets the second assistant.
		/// </summary>
		/// <value>The second assistant.</value>
		public User SecondAssistant
		{
			get { return RepositoryService.GetItem<User>(SecondAssistantID); }
			set
			{
				if ( value == null ) {
					SecondAssistantID = -1;
				} else {
					SecondAssistantID = value.ID;
				}
			}
		}

		/// <summary>
		/// Gets or sets the first manager ID.
		/// </summary>
		/// <value>The first manager ID.</value>
		public int FirstManagerID
		{
			get { return base.getInt("mgr1_user_id", -1); }
			set { base.setValue("FirstManagerID", "mgr1_user_id", value); }
		}

		/// <summary>
		/// Gets or sets the first manager.
		/// </summary>
		/// <value>The first manager.</value>
		public User FirstManager
		{
			get { return RepositoryService.GetItem<User>(FirstManagerID); }
			set
			{
				if ( value == null ) {
					FirstManagerID = -1;
				} else {
					FirstManagerID = value.ID;
				}
			}
		}

		/// <summary>
		/// Gets or sets the second manager ID.
		/// </summary>
		/// <value>The second manager ID.</value>
		public int SecondManagerID
		{
			get { return base.getInt("mgr2_user_id", -1); }
			set { base.setValue("SecondManagerID", "mgr2_user_id", value); }
		}

		/// <summary>
		/// Gets or sets the second manager.
		/// </summary>
		/// <value>The second manager.</value>
		public User SecondManager
		{
			get { return RepositoryService.GetItem<User>(SecondManagerID); }
			set
			{
				if ( value == null ) {
					SecondManagerID = -1;
				} else {
					SecondManagerID = value.ID;
				}
			}
		}

		/// <summary>
		/// Gets or sets the notes.
		/// </summary>
		/// <value>The notes.</value>
		public string Notes
		{
			get { return base.getString("notes", ""); }
			set { base.setValue("Notes", "notes", value); }
		}

		/// <summary>
		/// Gets or sets the time zone.
		/// </summary>
		/// <value>The time zone.</value>
		public int TimeZone
		{
			get { return base.getInt(_names.sColTimeZone, 0); }
			set { base.setValue("TimeZone", _names.sColTimeZone, value); }
		}

		/// <summary>
		/// Gets or sets a value indicating whether [day light savings].
		/// </summary>
		/// <value><c>true</c> if [day light savings]; otherwise, <c>false</c>.</value>
		public bool DayLightSavings
		{
			get { return base.getBool(_names.sColDayLightSavings, false); }
			set { base.setValue("DayLightSavings", _names.sColDayLightSavings, value); }
		}

		/// <summary>
		/// Gets or sets a value indicating whether this instance is system admin.
		/// </summary>
		/// <value>
		/// 	<c>true</c> if this instance is system admin; otherwise, <c>false</c>.
		/// </value>
		public bool IsSystemAdmin
		{
			get { return base.getBool(_names.sColSystemAdmin, false); }
			set { base.setValue("IsSystemAdmin", _names.sColSystemAdmin, value); }
		}

		/// <summary>
		/// Gets or sets a value indicating whether [enable email notifications].
		/// </summary>
		/// <value>
		/// 	<c>true</c> if [enable email notifications]; otherwise, <c>false</c>.
		/// </value>
		public bool EnableEmailNotifications
		{
			get { return base.getBool(_names.sColEmailNotification, false); }
			set { base.setValue("EnableEmailNotifications", _names.sColEmailNotification, value); }
		}

		/// <summary>
		/// Gets or sets a value indicating whether this instance is active user.
		/// </summary>
		/// <value>
		/// 	<c>true</c> if this instance is active user; otherwise, <c>false</c>.
		/// </value>
		public bool IsActiveUser
		{
			get { return base.getBool(_names.sColActive, false); }
			set { base.setValue("IsActiveUser", _names.sColActive, value); }
		}

		/// <summary>
		/// Gets or sets the show old activities.
		/// </summary>
		/// <value>The show old activities.</value>
		public int ShowOldActivities
		{
			get { return base.getInt("cmpl_activity_days", 0); }
			set { base.setValue("ShowOldActivities", "cmpl_activity_days", value); }
		}

		/// <summary>
		/// Gets or sets the screen resolution ID.
		/// </summary>
		/// <value>The screen resolution ID.</value>
		public int ScreenResolutionID
		{
			get { return base.getInt("screen_res_id", 0); }
			set { base.setValue("screen_res_id", "screen_res_id", value); }
		}
		/// <summary>
		/// Gets or sets the company.
		/// </summary>
		/// <value>The company.</value>
		public string Company
		{
			get { return base.getString("company", ""); }
			set { setValue("Company", "company", value); }
		}

		/// <summary>
		/// Called when [item deleting].
		/// </summary>
		protected override void OnItemDeleting()
		{
			base.OnItemDeleting();
			string usernm = this.UserName + "[" + this.ID.ToString() + "]";
			this.UserName = usernm.Substring(0, ( usernm.Length > 18 ? 18 : usernm.Length ));
			base.setValue("IsDeleted", "deleted_ind", true);
		}
		/// <summary>
		/// Called when [item deleted].
		/// </summary>
		protected override void OnItemDeleted()
		{
			base.OnItemDeleted();
		}

		#endregion

		#endregion

		#region Public Methods

		/// <summary>
		/// Gets the icon.
		/// </summary>
		/// <returns></returns>
		public override Icon GetIcon()
		{
			Bitmap bmp = new Bitmap(this.Image);
			bmp.MakeTransparent(Color.Magenta);
			return Icon.FromHandle(bmp.GetHicon());
		}

		/// <summary>
		/// Shows the new item form.
		/// </summary>
		/// <param name="idRepository">The repository ID.</param>
		/// <param name="bAllowContinue">if set to <c>true</c> to allow save and continue.</param>
		/// <param name="parentItem">The parent item.</param>
		/// <param name="idDomain">The domain ID.</param>
		/// <param name="parentItemNew">The new parent item.</param>
		/// <returns></returns>
		public override DialogResult ShowNewItemForm(int idRepository, bool bAllowContinue,
			IRepositoryItem parentItem, ref int idDomain, out IRepositoryItem parentItemNew)
		{
			FormCreateNewUser dlg = new FormCreateNewUser(this, bAllowContinue);
			dlg.DomainID = idDomain;
			dlg.ShowAllDomains = false;
			dlg.ShowAllFolders = false;
			dlg.FoldersVisible = false;
			dlg.DomainsVisible = false;
			dlg.ParentItem = parentItem;
			DialogResult result = dlg.ShowDialog();
			if ( result == DialogResult.OK || result == DialogResult.Retry ) {
				idDomain = dlg.DomainID;
				parentItemNew = dlg.NewParentItem;
			} else {
				idDomain = 0;
				parentItemNew = null;
			}
			return result;
		}

		/// <summary>
		/// Returns a <see cref="System.String"/> that represents this instance.
		/// </summary>
		/// <returns>
		/// A <see cref="System.String"/> that represents this instance.
		/// </returns>
		public override string ToString()
		{
			return string.Format("{0}, {1} {2}",
				LastName, FirstName, MiddleInitials);
		}

		/// <summary>
		/// Loads the item with the specified ID.
		/// </summary>
		/// <param name="id">The ID.</param>
		/// <returns></returns>
		public override bool Load(int id)
		{
			return base.Load(id);
		}

		/// <summary>
		/// Saves this instance.
		/// </summary>
		/// <returns></returns>
		public override bool Save()
		{
			if ( row[_names.sColUserName] != DBNull.Value ) {
				bool ok = base.Save();
				if ( ok ) {
					try {
						Global.Data.SetUserOrgUnit(this.ID, this.OrganizationUnitId);
					} catch ( Exception ex ) {
						Trace.WriteLine(ex.Message);
					}
				}
				return ok;
			} else {
				return false;
			}
		}

		/// <summary>
		/// Copies this instance.
		/// </summary>
		/// <param name="deep"><c>true</c> to recursively copy the item and all subitems;
		/// <c>false</c> to copy only the item itself.</param>
		/// <returns>The copied item.</returns>
		public override IRepositoryItem Copy(bool deep)
		{
			User copy = new User(true);
			copy.InitializeServiceProvider(this);
			this.CopyDataRowToTarget(copy);
			return copy;
		}

		#endregion

		#region Protected Methods

		/// <summary>
		/// Sets the default values.
		/// </summary>
		protected override void SetDefaultValues()
		{
			this.TimeZone = 1;
			this.LanguageId = 1;
			this.LanguageCode = 1033;
			this.ShowOldActivities = 0;
			this.ScreenResolutionID = 1;
			this.DayLightSavings = false;
			this.IsSystemAdmin = false;
			this.IsActiveUser = true;
			this.EnableEmailNotifications = false;
			base.setValue("IsDeleted", "deleted_ind", false);
			base.SetDefaultValues();
		}

		#endregion

		#region Private Methods
		void _roles_ListChanged(object sender, ListChangedEventArgs e)
		{
			if ( e.ListChangedType == ListChangedType.ItemAdded ) {
			}
		}
		#endregion

		#region Private Static Class: _names
		private static class _names
		{
			public const string sColEmployeeID = "personnel_id";
			public const string sColUserName = "user_nm";
			public const string sColPassword = "password";
			public const string sColOrgUnit = "person_orgunit";
			public const string sColRoles = "person_roles";
			public const string sColFirstName = "first_nm";
			public const string sColLastName = "last_nm";
			public const string sColMiddleName = "middle_nm";
			public const string sColTitle = "title";
			public const string sColDayLightSavings = "daylight_savings_ind";
			public const string sColSystemAdmin = "sa_ind";
			public const string sColEmailNotification = "email_activity_ind";
			public const string sColActive = "active_ind";
			public const string sColTimeZone = "tz_id";
		}
		#endregion

		#region IParticipant Members


		/// <summary>
		/// Gets the type of the participant.
		/// </summary>
		/// <value>The type of the participant.</value>
		public ParticipantType ParticipantType
		{
			get { return ParticipantType.User; }
		}

		#endregion

		#region IEquatable<IParticipant> Members

		/// <summary>
		/// Indicates whether the current object is equal to another object of the same type.
		/// </summary>
		/// <param name="other">An object to compare with this object.</param>
		/// <returns>
		/// true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.
		/// </returns>
		public bool Equals(IParticipant other)
		{
			return other != null && other.ParticipantType == this.ParticipantType && other.ID == this.ID;
		}

		#endregion
	}

}